package com.husd.framework.ddl_new;

import com.husd.framework.code.DDLColumn;
import com.husd.framework.code.ReferenceDefinition;
import org.apache.commons.lang3.StringUtils;

import java.util.ArrayList;
import java.util.List;

/**
 * 解析列声明
 *
 * @author shengdonghu@126.com
 * @date 2024/1/23 17:58
 */
public class MySQLTable0201ColumnParse {

    private List<List<String>> columnList;

    public MySQLTable0201ColumnParse(List<List<String>> columnList) {
        this.columnList = columnList;
    }

    public List<DDLColumn> parse() {

        List<DDLColumn> res = new ArrayList<>();

        for (List<String> sub : columnList) {

            DDLColumn ddlColumn = new DDLColumn();
            WordListScanner wordListScanner = new WordListScanner(sub);
            // create_definition 的类型：
            // col_name
            // index_name
            // index_type
            // key_part
            // index_option
            // symbol
            // reference_definition
            // check_constraint_definition
            CreateDefinitionTypeEnum _step = CreateDefinitionTypeEnum.create_definition;
            String next = "";
            String nextnext = "";
            String pre = "";
            String prepre = "";

            // 整体的策略就是发现了某一个关键字 就进入某个表达式的阶段 按这个表达式解析
            // 表达式后面如果是可选的 就直接break 表达式后面是必填的 就直接解析出来
            while (wordListScanner.haveWord()) {
                String current = wordListScanner.current();
                next = wordListScanner.getNextWord();
                nextnext = wordListScanner.getNextNextWord();
                pre = wordListScanner.getPreWord();
                prepre = wordListScanner.getPrePreWord();
                switch (current) {
                    case "bit": //java.lang.Boolean  >1 就是 byte[]
                    case "tinyint": // 如果 tinyInt1isBit 配置设置为 true(默认为 true)，是java.lang.Boolean，存储空间为 1；否则是为 java.lang.Integer
                    case "bool": // 参见 TINYINT。这些是 TINYINT(1) 另一种写法
                    case "boolean": // 参见 TINYINT。这些是 TINYINT(1) 另一种写法
                    case "smallint": // java.lang.Integer(不管是否无符)
                    case "mediumint":
                    case "integer":
                    case "int":
                    case "bigint":
                    case "float":
                    case "double":
                    case "decimal":
                    case "date":
                    case "datetime":
                    case "timestamp":
                    case "time":
                    case "year":
                    case "char":
                    case "varchar":
                    case "binary":
                    case "varbinary":
                    case "tinyblob":
                    case "tinytext":
                    case "blob":
                    case "text":
                    case "mediumblob":
                    case "mediumtext":
                    case "longblob":
                    case "longtext":
                    case "enum":
                    case "set":
                        if (_step == CreateDefinitionTypeEnum.reference_definition) {
                            break;
                        } else {
                            _step = CreateDefinitionTypeEnum.data_type;
                            Integer len = getColumnLen(wordListScanner);
                            boolean unsigned = wordListScanner.findWord("unsigned");
                            MysqlColumnDefine mysqlColumnDefine = MysqlColumnDefine.getMysqlColumnDefineByStr(current, len, unsigned);
                            // 以上都是mysql的列的类型
                            ddlColumn.setColumnType(mysqlColumnDefine.getJavaClass());
                            ddlColumn.setColumnLen(len);
                            if (len != null) {
                                // 把类型长度处理了 自动跳过去
                                wordListScanner.next(); // (
                                wordListScanner.next(); // 12
                                wordListScanner.next(); // )
                            }
                            break;
                        }
                    case "not":
                        if (_step == CreateDefinitionTypeEnum.column_definition) {
                            if (ParseUtil.isWord(next, "null")) {
                                ddlColumn.setNotNull(true);
                                wordListScanner.next();
                            }
                        }
                        if (_step == CreateDefinitionTypeEnum.check_constraint_definition) {
                            // ignore
                        }
                        break;
                    case "default":
                        if (_step == CreateDefinitionTypeEnum.column_definition
                                || _step == CreateDefinitionTypeEnum.data_type) {
                            // default 0
                            // default NULL
                            // default ''
                            // default (rand())
                            // default 'abc'
                            // 单引号和括号是需要单独处理的
                            if (ParseUtil.isWord(next, "'")) {
                                wordListScanner.next(); // 当前字符是左边的单引号了
                                String _default_val = wordListScanner.findMatchSamePair("'");
                                // 当前字符是右边的单引号了
                                ddlColumn.setDefaultVal(_default_val);
                            } else if (ParseUtil.isWord(next, "(")) {
                                wordListScanner.next(); // 当前字符是(了
                                String _default_val = wordListScanner.findMatchDiffPair("(", ")");
                                // 当前字符是)了
                                ddlColumn.setDefaultVal(_default_val);
                            } else {
                                ddlColumn.setDefaultVal(next);
                                wordListScanner.next();
                            }
                        }
                        break;
                    case "null":
                        if (_step == CreateDefinitionTypeEnum.column_definition
                                || _step == CreateDefinitionTypeEnum.data_type) {
                            if (ParseUtil.isWord(pre, "NOT")) {
                                ddlColumn.setNotNull(true);
                            } else if (ParseUtil.isWord(pre, "DEFAULT")) {
                                ddlColumn.setDefaultVal("NULL");
                            } else {
                                // 先默认为字段可以为null
                                ddlColumn.setNotNull(false);
                            }
                        }
                        break;
                    case "generated":
                        if (_step == CreateDefinitionTypeEnum.column_definition
                                || _step == CreateDefinitionTypeEnum.data_type) {
                            if (ParseUtil.isWord(next, "ALWAYS") && ParseUtil.isWord(nextnext, "AS")) {
                                wordListScanner.next(); // skip generated now is ALWAYS
                                wordListScanner.next(); // skip ALWAYS now is AS
                                wordListScanner.next(); // skip AS now is (
                                String _expr = wordListScanner.findMatchDiffPair("(", ")");
                                // now is )
                                ddlColumn.setGenerateAlwaysAs(_expr);
                            }
                        }
                        break;
                    case "always":
                        break;
                    case "virtual": //  [VIRTUAL | STORED] [NOT NULL | NULL]
                        if (_step == CreateDefinitionTypeEnum.column_definition
                                || _step == CreateDefinitionTypeEnum.data_type) {
                            if (ParseUtil.isWord(next, "NOT") && ParseUtil.isWord(nextnext, "NULL")) {
                                ddlColumn.setVirtual("NOT NULL");
                                // now is stored
                                wordListScanner.next(); // skip stored now is NOT
                                wordListScanner.next(); // skip NOT now is NULL
                            } else if (ParseUtil.isWord(next, "NULL")) {
                                ddlColumn.setVirtual("NULL");
                                wordListScanner.next(); // skip stored now is NULL
                            }
                        }
                        break;
                    case "stored":
                        if (_step == CreateDefinitionTypeEnum.column_definition
                                || _step == CreateDefinitionTypeEnum.data_type) {
                            if (ParseUtil.isWord(next, "NOT") && ParseUtil.isWord(nextnext, "NULL")) {
                                ddlColumn.setStored("NOT NULL");
                                // now is stored
                                wordListScanner.next(); // skip stored now is NOT
                                wordListScanner.next(); // skip NOT now is NULL
                            } else if (ParseUtil.isWord(next, "NULL")) {
                                ddlColumn.setStored("NULL");
                                wordListScanner.next(); // skip stored now is NULL
                            }
                        }
                        break;
                    case "visible":
                        if (_step == CreateDefinitionTypeEnum.column_definition
                                || _step == CreateDefinitionTypeEnum.data_type) {
                            ddlColumn.setVisible(true);
                        }
                    case "invisible":
                        if (_step == CreateDefinitionTypeEnum.column_definition
                                || _step == CreateDefinitionTypeEnum.data_type) {
                            ddlColumn.setVisible(false);
                        }
                        break; // 这2个都先忽略
                    case "auto_increment":
                        ddlColumn.setId(true); // 主键ID
                        break;
                    case "collate":
                        if (_step == CreateDefinitionTypeEnum.column_definition || _step == CreateDefinitionTypeEnum.data_type) {
                            String collationName = next;
                            ddlColumn.setCollationName(collationName);
                            wordListScanner.next(); // 把名字跳过去
                        }
                        break;
                    case "column_format":
                        if (_step == CreateDefinitionTypeEnum.column_definition
                                || _step == CreateDefinitionTypeEnum.data_type) {
                            if (ParseUtil.isWord(next, "FIXED") || ParseUtil.isWord(next, "DYNAMIC") || ParseUtil.isWord(next, "DEFAULT")) {
                                ddlColumn.setColumnFormat(next);
                                wordListScanner.next();
                            }
                        }
                        break;
                    case "engine_attribute":
                        if (_step == CreateDefinitionTypeEnum.column_definition
                                || _step == CreateDefinitionTypeEnum.data_type) {
                            if (ParseUtil.isWord(next, "=")) {
                                ddlColumn.setEngineAttribute(nextnext);
                            } else {
                                ddlColumn.setEngineAttribute(next);
                            }
                        }
                        break;
                    case "secondary_engine_attribute":
                        if (_step == CreateDefinitionTypeEnum.column_definition
                                || _step == CreateDefinitionTypeEnum.data_type) {
                            if (ParseUtil.isWord(next, "=")) {
                                ddlColumn.setSecondaryEngineAttribute(nextnext);
                            } else {
                                ddlColumn.setSecondaryEngineAttribute(next);
                            }
                        }
                        break;
                    case "storage":
                        if (_step == CreateDefinitionTypeEnum.column_definition
                                || _step == CreateDefinitionTypeEnum.data_type) {
                            if (ParseUtil.isWord(next, "DISK") || ParseUtil.isWord(next, "MEMORY")) {
                                ddlColumn.setStorage(next);
                            } else {
                                throw new RuntimeException("STORAGE属性不正确 应该是 {DISK | MEMORY} " + wordListScanner.debug());
                            }
                        }
                        break;
                    case "references":
                        _step = CreateDefinitionTypeEnum.reference_definition;
                        ReferenceDefinition referenceDefinition = new ReferenceDefinition();
                        String tblName = next;
                        referenceDefinition.setTblName(tblName);
                        List<String> keyPartList = new ArrayList<>();
                        wordListScanner.next();
                        if (ParseUtil.isWord(nextnext, "(")) {
                            wordListScanner.next(); // now is (
                            String _ref_word = wordListScanner.findMatchDiffPair("(", ")");
//                            String _ref_word = wordListScanner.current();
//                            while (!ParseUtil.isWord(_ref_word, ")") && wordListScanner.haveNext()) {
//                                if (!ParseUtil.isWord(_ref_word, ",")) {
//                                    keyPartList.add(_ref_word);
//                                }
//                                wordListScanner.next();
//                                _ref_word = wordListScanner.current();
//                            }
                            referenceDefinition.setKeyPart(_ref_word);
                            ddlColumn.setReferenceDefinition(referenceDefinition);
                            // 把右括号跳过去
                        } else {
                            throw new RuntimeException("REFERENCES属性不正确 没有指定key_part " + wordListScanner.debug());
                        }
                        break;
                    case "match":
                        if (_step == CreateDefinitionTypeEnum.reference_definition) {
                            ddlColumn.getReferenceDefinition().setMatch(next);
                            wordListScanner.next();
                        }
                        break;
                    case "delete":
                        if (_step == CreateDefinitionTypeEnum.reference_definition) {
                            if (ParseUtil.isWord(pre, "ON")) {
                                // reference_option 有可能是一个 有可能是2个
                                // RESTRICT | CASCADE | SET NULL | NO ACTION | SET DEFAULT
                                String _on_delete = next;
                                if (ParseUtil.isWord(_on_delete, "SET") || ParseUtil.isWord(_on_delete, "NO")) {
                                    _on_delete = next + " " + nextnext;
                                    ddlColumn.getReferenceDefinition().setOnDelete(_on_delete);
                                    wordListScanner.next();
                                    wordListScanner.next();
                                } else {
                                    ddlColumn.getReferenceDefinition().setOnDelete(_on_delete);
                                    wordListScanner.next();
                                }
                            }
                        }
                        break;
                    case "update":
                        if (_step == CreateDefinitionTypeEnum.reference_definition ||
                                _step == CreateDefinitionTypeEnum.data_type) {
                            if (ParseUtil.isWord(pre, "ON")) {
                                // reference_option 有可能是一个 有可能是2个
                                // RESTRICT | CASCADE | SET NULL | NO ACTION | SET DEFAULT
                                String _on_update = next;
                                if (ParseUtil.isWord(_on_update, "SET") || ParseUtil.isWord(_on_update, "NO")) {
                                    _on_update = next + " " + nextnext;
                                    ddlColumn.getReferenceDefinition().setOnUpdate(_on_update);
                                    wordListScanner.next();
                                    wordListScanner.next();
                                } else {
                                    ddlColumn.getReferenceDefinition().setOnUpdate(_on_update);
                                    wordListScanner.next();
                                }
                            }
                        }
                        break;
                    case "restrict":
                        break;
                    case "cascade":
                        break;
                    case "action":
                        break;
                    case "no":
                        break;
                    case "fixed":
                    case "dynamic":
                        break;
                    case "index":
                    case "key":
                        if (_step == CreateDefinitionTypeEnum.reference_definition ||
                                _step == CreateDefinitionTypeEnum.data_type) {
                            // 当前都先不处理key
                        }
                        break;
                    case "unique":
                        if (ParseUtil.isWord(next, "KEY")) {
                            wordListScanner.next(); // now is KEY ignore this KEY
                        }
                        ddlColumn.setUnique(true);
                        break;
                    case "fulltext":
                    case "spatial":
                    case "foreign":
                    case "primary":
                        if (ParseUtil.isWord(next, "KEY")) {
                            wordListScanner.next(); // now is KEY ignore this KEY
                        }
                        ddlColumn.setPrimary(true);
                        break;
                    case "ignore":
                        break;
                    case "replace":
                        break;
                    case "as":
                        _step = CreateDefinitionTypeEnum.query_expression;
                        break;
                    case "constraint":
                        // 什么都不做 在check关键字那里处理
                        break;
                    case "check":
                        // 这里要判断下接下来的是不是 check_constraint_definition
                        // check_constraint_definition 在2声明阶段都有
                        // 1 列声明阶段
                        // 2 索引声明阶段
                        // 要区分这2个阶段 这里从代码层面 保证了这里是1阶段
                        _step = CreateDefinitionTypeEnum.check_constraint_definition;
                        CheckConstraintDefinition checkConstraintDefinition =
                                new CheckConstraintDefinition();
                        ddlColumn.setCheckConstraintDefinition(checkConstraintDefinition);
                        if (ParseUtil.isWord(pre, "constraint")) {
                            checkConstraintDefinition.setConstraintSymbol(null);
                            wordListScanner.next(); // skip check now is (
                        } else {
                            checkConstraintDefinition.setConstraintSymbol(pre);
                            wordListScanner.next(); // skip symbol now is (
                        }
                        String _check_expr = wordListScanner.findMatchDiffPair("(", ")");
                        ddlColumn.getCheckConstraintDefinition().setCheckExpr(_check_expr);
                        break;
                    case "enforced":
                        if (_step == CreateDefinitionTypeEnum.check_constraint_definition) {
                            boolean _enforced = true;
                            if (ParseUtil.isWord(pre, "NOT")) {
                                _enforced = false;
                            }
                            ddlColumn.getCheckConstraintDefinition().setEnforced(_enforced);
                        }
                        break;
                    case "`":
                        break;
                    default:
                        // 普通字符的解析 要根据当前的阶段来处理
                        if (_step == CreateDefinitionTypeEnum.create_definition
                                || _step == CreateDefinitionTypeEnum.column_definition
                                || _step == CreateDefinitionTypeEnum.data_type) {
                            if (ParseUtil.isWord(pre, "(") || ParseUtil.isWord(pre, ",") || pre == null) {
                                ddlColumn.setColumnName(current);
                            } else if (ParseUtil.isWord(pre, "'") && ParseUtil.isWord(prepre, "DEFAULT") && ParseUtil.isWord(next, "'")) {
                                // [DEFAULT {literal | (expr)} ]
                                // fixme husd 需要处理 括号里是表达式的这种格式
                                ddlColumn.setDefaultVal(current);
                            } else if (ParseUtil.isWord(pre, "'") && ParseUtil.isWord(prepre, "COMMENT") && ParseUtil.isWord(next, "'")) {
                                ddlColumn.setComment(current);
                            }
                        }
                        break;
                }
                wordListScanner.next();
            }

            res.add(ddlColumn);
        }

        return res;
    }

    private Integer getColumnLen(WordListScanner wordListScanner) {

        String next = wordListScanner.getNextWord();
        String nextnext = wordListScanner.getNextNextWord();
        if (StringUtils.equalsIgnoreCase(next, "(") && StringUtils.isNumeric(nextnext)) {
            return Integer.parseInt(nextnext);
        }
        return null;
    }
}
